#pragma once

#include <array>
#include <atomic>
#include <cassert>
#include <cstdint>
#include <mutex>

#include "sleeper.h"

namespace good_cptl
{
struct MicroSpinLock
{
  enum {FREE = 0, LOCKED = 1};
  uint8_t lock_;
  void init() noexcept { payload()->store(FREE); }
  bool try_lock() noexcept
  {
    bool ret = xchg(LOCKED) == FREE;
    return ret;
  }

  void lock() noexcept
  {
    while (xchg(LOCKED) == FREE) {
      Sleeper sleeper;
      do {
        sleeper.wait();
      } while (payload()->load(std::memory_order_relaxed) == LOCKED);
    }
    assert(payload()->load() == LOCKED);
  }

  void unlock() noexcept
  {
    assert(payload()->load() == LOCKED);
    payload()->store(FREE, std::memory_order_release);
  }

private:
  std::atomic<uint8_t>* payload() noexcept
  {
    return reinterpret_cast<std::atomic<uint8_t>*>(&this->lock_);
  }

  uint8_t xchg(uint8_t new_val) noexcept
  {
    return std::atomic_exchange_explicit(
        payload(), new_val, std::memory_order_acq_rel
    );
  }
};


}